# -*- coding: utf-8 -*-

'''
这是CIE XYZ转换为Munsell色系的方法
具备初步功能，后续还需要更新
任何问题请联系邮箱：chinesevoice@163.com
'''

import pandas as pd
import math
import os

astm_lowchroma_datapath = os.getcwd().replace('\\','/') + '/basedata_astm2.csv'
astm_munselldatapath = os.getcwd().replace('\\','/') + '/basedata_astm1.csv'

def pts_in_tri(x1,y1,x2,y2,x3,y3,x,y):
    #重心坐标系法判断点与三角形的位置关系
    lam_up1 = (y2-y3) * (x-x3) + (x3-x2) * (y-y3)
    lam_down1 = (y2-y3) * (x1-x3) + (x3-x2) * (y1-y3)
    lam1 = lam_up1 / lam_down1
    lam_up2 = (y3-y1) * (x-x3) + (x1-x3) * (y-y3)
    lam_down2 = (y2-y3) * (x1-x3) + (x3-x2) * (y1-y3)
    lam2 = lam_up2 / lam_down2
    lam3 = 1 - lam1 - lam2
    if lam1 > 0 and lam1 < 1 and lam2 > 0 and lam2 < 1 and lam3 > 0 and lam3 < 1:
        return True
    elif lam1 >= 0 and lam1 <= 1 and lam2 >= 0 and lam2 <= 1 and lam3 >= 0 and lam3 <= 1:
        raise 'point on-line in the low chroma'
    else:
        return False

def is_in_tri(v,x,y):
    basedata = pd.read_csv(astm_lowchroma_datapath)
    rows = basedata.shape[0]
    #白点位置
    x0,y0 = 0.3101,0.3163
    for row_idx in range(rows):
        #找到匹配的亮度值
        v_astm = basedata.iloc[row_idx,3]
        if v_astm == v:
            x1,y1 = basedata.iloc[row_idx,5],basedata.iloc[row_idx,6]
            x2,y2 = basedata.iloc[row_idx,10],basedata.iloc[row_idx,11]
            flag = pts_in_tri(x0,y0,x1,y1,x2,y2,x,y)
            if flag:
                h1,c1 = basedata.iloc[row_idx,2],basedata.iloc[row_idx,4]
                h2,c2 = basedata.iloc[row_idx,8],basedata.iloc[row_idx,9]
                point = [x1,y1,h1,c1,x2,y2,h2,c2]
                return flag,point
            else:
                pass
    point = None
    return flag,point

#求直线交点，前提是具备相交条件
def cross_line_point(a1,b1,c1,a2,b2,c2):
    m = a1 * b2 - a2 * b1
    if m==0:
        raise 'error: no cross line point.'
    else:
        x = (c2 * b1 - c1 * b2) / m
        y = (c1 * a2 - c2 * a1) / m
    return x,y

#平行线法计算H
def v_hue2(x,y,point_A,point_B,point_D):
    xA,yA,HA,CA = point_A[0],point_A[1],point_A[2],point_A[3]
    xB,yB,HB,CB = point_B[0],point_B[1],point_B[2],point_B[3]
    xD,yD,HD,CD = point_D[0],point_D[1],point_D[2],point_D[3]
    #保证B点与D点的H值是递增的
    if HB == 100 and HD == 2.5:
        HB = 0
    #求AP直线
    para_a1 = y - yA
    para_b1 = xA - x
    para_c1 = x * yA - xA * y
    #求BD直线
    para_a2 = yD - yB
    para_b2 = xB - xD
    para_c2 = xD * yB - xB * yD
    #求AP直线与BD直线的交点M
    xm,ym = cross_line_point(para_a1,para_b1,para_c1,para_a2,para_b2,para_c2)
    #BM长度，DM长度
    BM_len = math.sqrt((xB - xm)**2 + (yB - ym)**2)
    MD_len = math.sqrt((xD - xm)**2 + (yD - ym)**2)
    ratio = BM_len / MD_len
    #求HP
    HP = (HD * ratio + HB) / (1 + ratio)
    return HP

#H值与其数值之间的转换
def hnum_h(hnum):
    if hnum > 0 and hnum <= 10:
        h = str(round(hnum - 0,2)) + 'R'
    elif hnum > 10 and hnum <= 20:
        h = str(round(hnum - 10,2)) + 'YR'
    elif hnum > 20 and hnum <= 30:
        h = str(round(hnum - 20,2)) + 'Y'
    elif hnum > 30 and hnum <= 40:
        h = str(round(hnum - 30,2)) + 'GY'
    elif hnum > 40 and hnum <= 50:
        h = str(round(hnum - 40,2)) + 'G'
    elif hnum > 50 and hnum <= 60:
        h = str(round(hnum - 50,2)) + 'BG'
    elif hnum > 60 and hnum <= 70:
        h = str(round(hnum - 60,2)) + 'B'
    elif hnum > 70 and hnum <= 80:
        h = str(round(hnum - 70,2)) + 'PB'
    elif hnum > 80 and hnum <= 90:
        h = str(round(hnum - 80,2)) + 'P'
    elif hnum > 90 and hnum <= 100:
        h = str(round(hnum - 90,2)) + 'RP'
    else:
        raise 'Hue value out of range: (0,100]'
    return h

#根据Y求亮度值V
def calculate_v(Y):
    A = 2.49268
    B = 1.5614
    C = 0.985
    D = 0.1073
    E = 3.084
    F = 7.54
    G = 0.0133
    H = 2.3
    J = 0.0084
    K = 4.1
    M = 0.0221
    N = 0.39
    P = 0.0037
    Q = 0.44
    S = 1.28
    T = 0.53
    U = 0.87445
    W = 0.9967
    if Y <= 0.9:
        v = U * math.pow(Y, W)
    else:
        v = A * math.pow(Y, 0.33333333) - B - C/(math.pow(D * Y - E,2) + F)\
        + G /math.pow(Y,H) + J * math.sin(K * math.pow(Y,0.33333333) + 1) + \
        (M/Y) * math.sin(N * (Y-2))-(P/(Q * Y)) * math.sin(S * (Y-T))
    return round(v,4)

def limit_v(v):
    if v >= 1 and v <= 9:
        return v
    elif v > 9 and v <= 9.5:
        v = 9
        return v
    elif v >= 0.5 and v < 1:
        v = 1
        return v
    else:
        raise 'Error: the value out of range which must between 1 and 9'
    pass

def v_uplow(v):
    v = limit_v(v)
    v1 = math.ceil(v) 
    v2 = math.floor(v)
    return v1,v2

#找到距离最近的三个点
def find_tripoint(x,y,v,r,astm_munselldatapath):
    data_astm = pd.read_csv(astm_munselldatapath)
    rows = data_astm.shape[0]
    dict_dandrow = {} #字典用来存储距离和行号
    for row_idx in range(rows):
        if data_astm.iloc[row_idx,3] == v:
            x_ = data_astm.iloc[row_idx,5] 
            y_ = data_astm.iloc[row_idx,6] 
            d = math.pow(x - x_,2) + math.pow(y - y_,2)
            #字典存储一个行号对应一个距离
            dict_dandrow[row_idx] = d
        else:
            pass
    #对字典按值排序，升序，前三个为d最小的点，即距离最短三点
    list_dandrow = sorted(dict_dandrow.items(),
                          key=lambda x:x[1],reverse=False)
    #提取最短距离
    row_init = list_dandrow[0][0]
    x1 = data_astm.iloc[row_init,5]
    y1 = data_astm.iloc[row_init,6]
    min_d = math.sqrt(math.pow(x - x1,2) + math.pow(y - y1,2))
    p,pts = is_in_tri(v,x,y)
    if min_d < 0.001:
        point_A = False
        point_B = data_astm.iloc[row_init,2]
        point_D = data_astm.iloc[row_init,4]
        return point_A,point_B,point_D
    elif p:
        point_A = [0.3101,0.3163,0,0]
        point_B = [pts[0],pts[1],pts[2],pts[3]]
        point_D = [pts[4],pts[5],pts[6],pts[7]]
        return point_A,point_B,point_D
    else:
        #对list_dandrow进行适当调整，保证前三项H,C不全等
        #分两种情况，分别针对H和C
        list_dandrow = reset_tripoint(data_astm,list_dandrow,r)
        #读取前三个点对应的行数
        row_a = list_dandrow[0][0]
        row_b = list_dandrow[1][0]
        row_d = list_dandrow[2][0]
        #根据行数提取数据，每个点分别对应提取x,y,H,C
        point_A = [data_astm.iloc[row_a,5],data_astm.iloc[row_a,6],
                   data_astm.iloc[row_a,2],data_astm.iloc[row_a,4]]
        point_B = [data_astm.iloc[row_b,5],data_astm.iloc[row_b,6],
                   data_astm.iloc[row_b,2],data_astm.iloc[row_b,4]]
        point_D = [data_astm.iloc[row_d,5],data_astm.iloc[row_d,6],
                   data_astm.iloc[row_d,2],data_astm.iloc[row_d,4]]
        return point_A,point_B,point_D

def reset_tripoint(data,dct,item):
    #item选择hue或者chroma,1代表hue，2代表chroma
    if item == 1:
        dct = adjust_hue(data,dct)
        #提取前三个元素的key值，即行数
        r1,r2,r3 = dct[0][0],dct[1][0],dct[2][0]
        HA,HB,HD = data.iloc[r1,2],data.iloc[r2,2],data.iloc[r3,2]
        CA,CB,CD = data.iloc[r1,4],data.iloc[r2,4],data.iloc[r3,4]
        #i代表从第四个开始，依次与第三个互换
        #一直达到前三个不全等为止
        i = 3
        #循环的条件就是前三是否全等，若全等，则一直循环
        while HA == HB == HD or CA == CB == CD or abs(HA - HB) > 50:
            dct[0],dct[i] = dct[i],dct[0]
            i += 1
            r1,r2,r3 = dct[0][0],dct[1][0],dct[2][0]
            HA,HB,HD = data.iloc[r1,2],data.iloc[r2,2],data.iloc[r3,2]
            CA,CB,CD = data.iloc[r1,4],data.iloc[r2,4],data.iloc[r3,4]
        j = 3
        while HA == HB == HD or CA == CB == CD or \
        abs(HB - HD) > 50 or abs(HA - HD) > 50:
            dct[2],dct[j] = dct[j],dct[2]
            j += 1
            r1,r2,r3 = dct[0][0],dct[1][0],dct[2][0]
            HA,HB,HD = data.iloc[r1,2],data.iloc[r2,2],data.iloc[r3,2]
            CA,CB,CD = data.iloc[r1,4],data.iloc[r2,4],data.iloc[r3,4]
        return dct
    elif item == 2:
        r1,r2,r3 = dct[0][0],dct[1][0],dct[2][0]
        HA,HB,HD = data.iloc[r1,2],data.iloc[r2,2],data.iloc[r3,2]
        CA,CB,CD = data.iloc[r1,4],data.iloc[r2,4],data.iloc[r3,4]
        i = 3
        while HA == HB == HD or CA == CB == CD:
            dct[2],dct[i] = dct[i],dct[2]
            i += 1
            r1,r2,r3 = dct[0][0],dct[1][0],dct[2][0]
            HA,HB,HD = data.iloc[r1,2],data.iloc[r2,2],data.iloc[r3,2]
            CA,CB,CD = data.iloc[r1,4],data.iloc[r2,4],data.iloc[r3,4]
        return dct
    else:
        raise 'Error: wrong value of item = 1 or 2'
    pass

def adjust_hue(data,dct):
    r1,r2,r3 = dct[0][0],dct[1][0],dct[2][0]
    HA,HB,HD = data.iloc[r1,2],data.iloc[r2,2],data.iloc[r3,2]
    if HA > HB:
        dct[0],dct[1],HA,HB = dct[1],dct[0],HB,HA
    if HA > HD:
        dct[0],dct[2],HA,HD = dct[2],dct[0],HD,HA
    if HB > HD:
        dct[1],dct[2],HB,HD = dct[2],dct[1],HD,HB
    return dct

#对ABD三点重新分配，保证hue按照升序排列
def reclass_pointABDwithHue(point_A,point_B,point_D):
    HA = point_A[2]
    HB = point_B[2]
    HD = point_D[2]
    if HA > HB:
        point_A,point_B,HA,HB = point_B,point_A,HB,HA
    if HA > HD:
        point_A,point_D,HA,HD = point_D,point_A,HD,HA
    if HB > HD:
        point_B,point_D,HB,HD = point_D,point_B,HD,HB
    return point_A,point_B,point_D

#对ABD三点重新分配，保证chroma按照升序排列
def reclass_pointABDwithChroma(point_A,point_B,point_D):
    CA = point_A[3]
    CB = point_B[3]
    CD = point_D[3]
    if CA > CB:
        point_A,point_B,CA,CB = point_B,point_A,CB,CA
    if CA > CD:
        point_A,point_D,CA,CD = point_D,point_A,CD,CA
    if CB > CD:
        point_B,point_D,CB,CD = point_D,point_B,CD,CB
    return point_A,point_B,point_D

#解一元二次方程组，求m点坐标的前奏
def quadratic(a,b,c):
    delta = b * b -4 * a * c
    if delta >= 0 and a != 0:
        x1 = (-b + math.sqrt(delta))/(2 * a)
        x2 = (-b - math.sqrt(delta))/(2 * a)
        return x1,x2
    elif a == 0:
        x1=x2=-c/b
        return x1,x2
    else:
        x1=x2=None
        return x1,x2

#计算出最终确定的唯一的xm坐标
def calc_xm(x1,x2,xa,xd):
    if xa > xd:
        xa,xd = xd,xa
    if x1 == None:
        return x1
    elif x1 == x2 and x1 <= xd and x1 >= xa:
        return x1
    elif x1 <= xd and x1 >= xa:
        return x1
    elif x2 <= xd and x2 >= xa:
        return x2
    else:
        return None
 
#如果有两个点hue一样，则排序至AB两点一样，以便计算
def resorted_samehue(xA,yA,HA,CA,HB,xD,yD,HD,CD):
    if HA == HB:
        pass
    elif HB == HD:
        xA,yA,HA,CA,xD,yD,HD,CD = xD,yD,HD,CD,xA,yA,HA,CA
    else:
        raise 'Error: same hue but can not calculate.'
    return xA,yA,HA,CA,xD,yD,HD,CD

#如果有两个点chroma一样，则排序至AB两点一样，以便计算
def resorted_samechroma(xA,yA,HA,CA,CB,xD,yD,HD,CD):
    if CA == CB:
        pass
    elif CB == CD:
        xA,yA,HA,CA,xD,yD,HD,CD = xD,yD,HD,CD,xA,yA,HA,CA
    else:
        raise 'Error: same hue but can not calculate.'
    return xA,yA,HA,CA,xD,yD,HD,CD

def v_hue(x,y,v,astm_munselldatapath):
    point_A,point_B,point_D = find_tripoint(x,y,v,1,astm_munselldatapath)
    if point_A == False:
        HP = point_B
        return HP
    elif point_A[2] == point_A[3] == 0:
        HP = v_hue2(x,y,point_A,point_B,point_D)
        return HP
    else:
        point_A,point_B,point_D = reclass_pointABDwithHue(point_A,point_B,point_D)
        xA,yA,HA,CA = point_A[0],point_A[1],point_A[2],point_A[3]
        xB,yB,HB,CB = point_B[0],point_B[1],point_B[2],point_B[3]
        xD,yD,HD,CD = point_D[0],point_D[1],point_D[2],point_D[3]
        #对三个点的数据进行判断，选择合适计算方式计算H
        if len(set([HA,HB,HD])) == 3:
            #求DA直线方程:y - yA = k_DA * (x - xA)
            #斜率k
            k_DA = (yD - yA)/(xD - xA)
            #假设一点M(xm,ym)
            delta_h = abs(HD - HB)/abs(HB - HA)
            #一元二次方程参数
            para_a = math.pow(delta_h, 2) - 1
            para_b = 2 * xD - 2 * xA * math.pow(delta_h, 2)
            para_c = math.pow(delta_h, 2) * math.pow(xA, 2) - math.pow(xD, 2)
            x1,x2 = quadratic(para_a,para_b,para_c)
            xm = calc_xm(x1,x2,xA,xD)
            if xm == None:
                raise 'Error: xm = None'
            else:
                #求出M(xm,ym)
                ym = k_DA * (xm - xA) + yA
                #求直线BM的方程一般式,已知两点B，M
                BM_paraA = ym - yB
                BM_paraB = xB - xm
                BM_paraC = xm * yB - xB * ym
                pnt_p = BM_paraA * x + BM_paraB * y + BM_paraC
                pnt_A = BM_paraA * xA + BM_paraB * yA + BM_paraC
                pnt_D = BM_paraA * xD + BM_paraB * yD + BM_paraC
                if pnt_p == 0:
                    # Info: point P on the BM line.'
                    HP = HB
                    return HP
                elif pnt_p * pnt_A > 0:
                    s1 = abs(BM_paraA * x + BM_paraB * y + BM_paraC)
                    s2 = abs(BM_paraA * xA + BM_paraB * yA + BM_paraC)
                    s = s1 / s2
                    HP = HB + s * (HA - HB)
                    if HP <= 0:
                        HP = HP + 100
                    elif HP > 100:
                        HP = HP - 100
                    else:
                        pass
                    return HP
                elif pnt_p * pnt_D > 0:
                    s1 = abs(BM_paraA * x + BM_paraB * y + BM_paraC)
                    s2 = abs(BM_paraA * xD + BM_paraB * yD + BM_paraC)
                    s = s1 / s2
                    HP = HB + s * (HD - HB)
                    if HP <= 0:
                        HP = HP + 100
                    elif HP > 100:
                        HP = HP - 100
                    else:
                        pass
                    return HP
                else:
                    raise 'Error: can not calc point position.'
        elif len(set([HA,HB,HD])) == 2:
            xA,yA,HA,CA,xD,yD,HD,CD = resorted_samehue(xA,yA,HA,CA,HB,xD,yD,HD,CD)
            #求直线AB方程一般式参数
            AB_paraA = yB - yA
            AB_paraB = xA - xB
            AB_paraC = xB * yA - xA * yB
            pnt_p2 = AB_paraA * x + AB_paraB * y + AB_paraC
            pnt_D2 = AB_paraA * xD + AB_paraB * yD + AB_paraC
            if pnt_p2 == 0:
                # Info: point P on the AB line.'
                HP = HA
                return HP
            elif pnt_p2 * pnt_D2 > 0:
                s1 = abs(AB_paraA * x + AB_paraB * y + AB_paraC)
                s2 = abs(AB_paraA * xD + AB_paraB * yD + AB_paraC)
                s = s1 / s2
                HP = HB + s * (HD - HB)
                if HP <= 0:
                    HP = HP + 100
                elif HP > 100:
                    HP = HP - 100
                else:
                    pass
                return HP
            elif pnt_p2 * pnt_D2 < 0:
                s1 = abs(AB_paraA * x + AB_paraB * y + AB_paraC)
                s2 = abs(AB_paraA * xD + AB_paraB * yD + AB_paraC)
                s = s1 / s2
                HP = s * (HB - HD) + HB
                HP = HB + s * (HD - HB)
                if HP <= 0:
                    HP = HP + 100
                elif HP > 100:
                    HP = HP - 100
                else:
                    pass
                return HP
            else:
                raise 'Error: can not calculate.' 
        else:
            raise 'The same Hue. 1'

def v_chroma(x,y,v,astm_munselldatapath):
    point_A,point_B,point_D = find_tripoint(x,y,v,2,astm_munselldatapath)
    if point_A == False:
        CP = point_D
        return CP
    else:
        point_A,point_B,point_D = reclass_pointABDwithChroma(point_A,point_B,point_D)
        xA,yA,HA,CA = point_A[0],point_A[1],point_A[2],point_A[3]
        xB,yB,HB,CB = point_B[0],point_B[1],point_B[2],point_B[3]
        xD,yD,HD,CD = point_D[0],point_D[1],point_D[2],point_D[3]
        #对三个点的数据进行判断，选择合适计算方式计算C
        if len(set([CA,CB,CD])) == 3:
            #求DA直线方程:y - yA = k_DA * (x - xA)
            #斜率k
            k_DA = (yD - yA)/(xD - xA)
            #假设一点M(xm,ym)
            delta_c = abs(CD - CB) / abs(CB - CA)
            #一元二次方程参数
            para_a = math.pow(delta_c, 2) - 1
            para_b = 2 * xD - 2 * xA * math.pow(delta_c, 2)
            para_c = math.pow(delta_c, 2) * math.pow(xA, 2) - math.pow(xD, 2)
            x1,x2 = quadratic(para_a,para_b,para_c)
            xm = calc_xm(x1,x2,xA,xD)
            if xm == None:
                raise 'Error: xm = None'
            else:
                #求出M(xm,ym)
                ym = k_DA * (xm - xA) + yA
                #求直线BM的方程一般式,已知两点B，M
                BM_paraA = ym - yB
                BM_paraB = xB - xm
                BM_paraC = xm * yB - xB * ym
                pnt_p = BM_paraA * x + BM_paraB * y + BM_paraC
                pnt_A = BM_paraA * xA + BM_paraB * yA + BM_paraC
                pnt_D = BM_paraA * xD + BM_paraB * yD + BM_paraC
                if pnt_p == 0:
                    #Info: point P on the BM line.'
                    CP = CB
                    return CP
                elif pnt_p * pnt_A > 0:
                    s1 = abs(BM_paraA * x + BM_paraB * y + BM_paraC)
                    s2 = abs(BM_paraA * xA + BM_paraB * yA + BM_paraC)
                    s = s1 / s2
                    CP = CB + s * (CA - CB)
                    return CP
                elif pnt_p * pnt_D > 0:
                    s1 = abs(BM_paraA * x + BM_paraB * y + BM_paraC)
                    s2 = abs(BM_paraA * xD + BM_paraB * yD + BM_paraC)
                    s = s1 / s2
                    CP = CB + s * (CD - CB)
                    return CP
                else:
                    raise 'Error: can not calc point position.'
        elif len(set([CA,CB,CD])) == 2:
            xA,yA,HA,CA,xD,yD,HD,CD = resorted_samechroma(xA,yA,HA,CA,CB,xD,yD,HD,CD)
            #求直线AB方程一般式参数
            AB_paraA = yB - yA
            AB_paraB = xA - xB
            AB_paraC = xB * yA - xA * yB
            pnt_p2 = AB_paraA * x + AB_paraB * y + AB_paraC
            pnt_D2 = AB_paraA * xD + AB_paraB * yD + AB_paraC
            if pnt_p2 == 0:
                #Info: point P on the AB line.'
                CP = CA
                return CP
            elif pnt_p2 * pnt_D2 > 0:
                s1 = abs(AB_paraA * x + AB_paraB * y + AB_paraC)
                s2 = abs(AB_paraA * xD + AB_paraB * yD + AB_paraC)
                s = s1 / s2
                CP = CB + s * (CD - CB)
                return CP
            elif pnt_p2 * pnt_D2 < 0:
                s1 = abs(AB_paraA * x + AB_paraB * y + AB_paraC)
                s2 = abs(AB_paraA * xD + AB_paraB * yD + AB_paraC)
                s = s1 / s2
                CP = s * (CB - CD) + CB
                return CP
            else:
                raise 'Error: can not calculate.' 
        else:
            raise 'The same Chroma. 1'

#在0.3的亮度容差上对H,C进行弹性取舍
def adjust_hueandchroma(v,h1,h2,h3,c1,c2,c3):
    v_up,v_down = v_uplow(v)
    if v - v_down < 0.3:
        hue,chroma = h2,c2
    elif v_up - v < 0.3:
        hue,chroma = h1,c1
    else:
        hue,chroma = h3,c3
    return hue,chroma

def converter(X,Y,Z,astm_munselldatapath):
    x = X / (X+Y+Z)
    y = Y / (X+Y+Z)
    V = calculate_v(Y)
    #判断是否为N中性
    Nd = math.sqrt((x-0.3101)**2 + (y-0.3163)**2)
    if Nd < 0.001 or V > 9.5 or V < 0.5:
        return str(0),0,V,0
    #判断是否在三角形内
    else:
        v_up, v_low = v_uplow(V)
        v_uphue = v_hue(x,y,v_up,astm_munselldatapath)
        v_upchroma = v_chroma(x,y,v_up,astm_munselldatapath)
        v_lowhue = v_hue(x,y,v_low,astm_munselldatapath)
        v_lowchroma = v_chroma(x,y,v_low,astm_munselldatapath)
        if abs(v_lowhue - v_uphue) > 50:
            if v_lowhue < v_uphue:
                v_uphue = v_uphue - 100
                hp = v_lowhue + (V - v_low) * (v_uphue - v_lowhue)
                if hp <= 0:
                    hp = hp + 100
                else:
                    pass
                v_uphue = v_uphue + 100
            else:
                v_lowhue -= 100
                hp = v_lowhue + (V - v_low) * (v_uphue - v_lowhue)
                if hp <= 0:
                    hp = hp + 100
                else:
                    pass
                v_lowhue = v_lowhue + 100
        else:
            hp = v_lowhue + (V - v_low) * (v_uphue - v_lowhue)
        cp = v_lowchroma + (V - v_low) * (v_upchroma - v_lowchroma)
        #输出等明面上的值和计算的中间值
        h1,h2,h3 = round(v_uphue,4),round(v_lowhue,4),round(hp,4)
        c1,c2,c3 = round(v_upchroma,4),round(v_lowchroma,4),round(cp,4)
        hue,chroma = adjust_hueandchroma(V,h1,h2,h3,c1,c2,c3)
        h_str = hnum_h(hue)
        return h_str,hue,V,chroma

if __name__ == '__main__':
    X = 14.1789
    Y = 14.1537
    Z = 11.728
    h_str,hue,V,chroma = converter(X,Y,Z,astm_munselldatapath)
    print(h_str,hue,V,chroma)